pragma ComponentBehavior: Bound
import QtQml
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
import qs.modules.waffle.looks

Item {
    id: root

    // Expose delegate
    property Component delegate: Text {
        required property var model
        text: model.day
    }

    // Configuration
    property int paddingWeeks: 2 // 1 should be sufficient with proper clipping and no padding
    property var locale: Qt.locale() // Should be of type Locale but QML is being funny

    // Scrolling
    function scrollMonthsAndSnap(x) { // Scroll x months and snap to month
        const focusedDate = root.focusedDate;
        const focusedMonth = focusedDate.getMonth();
        const focusedYear = focusedDate.getFullYear();
        const targetMonth = focusedMonth + x;
        const targetDate = new Date(focusedYear, targetMonth, 1);
        const currentFirstShownDate = new Date(root.dateInFirstWeek.getTime() + (root.paddingWeeks * root.millisPerWeek));
        const diffMillis = targetDate.getTime() - currentFirstShownDate.getTime();
        const diffWeeks = Math.round(diffMillis / root.millisPerWeek);
        root.targetWeekDiff += diffWeeks;
    }
    property int weeksPerScroll: 1
    property real targetWeekDiff: 0
    property real weekDiff: targetWeekDiff
    property int contentWeekDiff: weekDiff // whole part of weekDiff
    property bool scrolling: false

    Behavior on weekDiff {
        id: weekScrollBehavior
        animation: Looks.transition.scroll.createObject(this)
    }
    Timer {
        id: scrollAnimationCheckTimer
        interval: 30 // Should be plenty for 60fps
        onTriggered: root.scrolling = false;
    }
    onWeekDiffChanged: {
        scrolling = true;
        scrollAnimationCheckTimer.restart();
    }

    MouseArea {
        anchors.fill: parent
        onWheel: wheel => {
            root.targetWeekDiff += wheel.angleDelta.y / 120 * -root.weeksPerScroll; // Reverse cuz scrolling down should advance
        }
    }

    // Date calculations
    readonly property int millisPerWeek: 7 * 24 * 60 * 60 * 1000
    readonly property int totalWeeks: 6 + (paddingWeeks * 2)
    readonly property int focusedWeekIndex: 2 // The third row, 0-indexed
    readonly property int focusDayOfWeekIndex: 6
    property date dateInFirstWeek: {
        const currentDate = new Date();
        const currentMonth = currentDate.getMonth();
        const currentYear = currentDate.getFullYear();
        const firstDayThisMonth = new Date(currentYear, currentMonth, 1);
        return new Date(firstDayThisMonth.getTime() - (paddingWeeks * millisPerWeek) + contentWeekDiff * millisPerWeek);
    }
    property date focusedDate: {
        // The last day of 3rd week shown is considered the focused month
        const addedTime = (root.paddingWeeks + root.focusedWeekIndex) * root.millisPerWeek
        const dateInTargetWeek = new Date(root.dateInFirstWeek.getTime() + addedTime);
        return DateUtils.getIthDayDateOfSameWeek(dateInTargetWeek, root.focusDayOfWeekIndex - root.locale.firstDayOfWeek, root.locale.firstdayOfWeek); // 4 = Thursday
    }
    property int focusedMonth: focusedDate.getMonth() + 1 // 0-indexed -> 1-indexed

    // Sizes
    property real verticalPadding: 0
    property real buttonSize: 40
    property real buttonSpacing: 2
    implicitHeight: (6 * buttonSize) + (5 * buttonSpacing) + (2 * verticalPadding)
    implicitWidth: weeksColumn.implicitWidth
    clip: true
    
    ColumnLayout {
        id: weeksColumn
        anchors {
            left: parent.left
            right: parent.right
        }
        y: {
            const spacePerExtraRow = root.buttonSize + root.buttonSpacing;
            const origin = -(spacePerExtraRow * root.paddingWeeks);
            const diff = root.weekDiff * spacePerExtraRow;
            return origin + (-diff % spacePerExtraRow) + root.verticalPadding;
        }

        spacing: root.buttonSpacing
        
        Repeater {
            model: root.totalWeeks

            WeekRow {
                required property int index
                locale: root.locale
                date: new Date(root.dateInFirstWeek.getTime() + (index * root.millisPerWeek))
                Layout.fillWidth: true
                spacing: root.buttonSpacing
                delegate: root.delegate
            }
        }
    }
}
